;; host/tcp.scm - (c) rohan drape, 2002-2005

;; Mechanism for sending and receiving length prefixed byte packets
;; over a TCP connection.  The length prefix is a four byte network
;; order signed integer.  This is the form of OSC packets over TCP.
;; See also udp.scm.

(define-structure tcp-client (thread-token 
			       input-port 
			       output-port))

;; Establish TCP connection to `address'.  Incoming datagrams
;; are handled by `receiver', which is a two argument procedure
;; accepting a <network-address> and a <u8vector>.

(defineV (make-tcp-client address receiver)
  (let* ((host-address (network-address-host-address address))
	 (port-number (network-address-port-number address))
	 (host-name (host-address->host-name host-address)))
    (receive 
     (input-port output-port) 
     (tcp-connect host-name port-number)
     (make-tcp-client*
      (make-thread*
       (lambda ()
	 (let loop ()
	   (let ((size (read-u8vector 4 input-port)))
	     (if (not (eof-object? size))
		 (let ((packet-size (u8vector->integer size #t #t)))
		   (receiver address 
			     (read-u8vector packet-size input-port))
		   (loop)))))))
      input-port 
      output-port))))

;; Send the <u8vector> `packet' using `t'.

(define (tcp-client-send t packet)
  (let ((output-port (tcp-client-output-port t)))
    (display (integer->u8vector (u8vector-length packet)
				4
				#t
				#t)
	     output-port)
    (write-u8vector packet output-port)))

;; Stop the receiver thread, and close the connection at
;; `t'.

(define (tcp-client-stop t)
  (thread-terminate! (tcp-client-thread-token t))
  (close-input-port (tcp-client-input-port t))
  (close-output-port (tcp-client-output-port t)))
